package com.zhang.learns.netty;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.List;

@Slf4j
public class Boss implements Runnable {
    /**
     * 服务端口
     */
    private int serverPort;

    /**
     * 启动服务监听的线程
     */
    private Thread bossThread;

    /**
     * 单例的对象实例
     */
    private static volatile Boss instance;

    /**
     * 客户端处理程序
     */
    private List<Worker> workers;

    /**
     * 私有的构造器，只能执行一次
     *
     * @param serverPort
     */
    private Boss(int serverPort, List<Worker> workers) {
        if (serverPort == 0) {
            throw new RuntimeException("Boss端服务端口不能为空！");
        }
        this.serverPort = serverPort;
        if (workers == null || workers.size() < 1) {
            throw new RuntimeException("Workers列表不能为空！");
        }
        this.workers = workers;

        Thread thread = new Thread(this, "boss");
        thread.start();
        this.bossThread = thread;
        log.info("boss已启动");
    }

    public static Boss start(int serverPort, List<Worker> workers) {
        if (instance == null) {
            synchronized (Boss.class) {
                if (instance == null) {
                    instance = new Boss(serverPort, workers);
                }
            }
        }
        return instance;
    }

    @Override
    public void run() {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(serverPort));
            serverSocketChannel.configureBlocking(false);

            Selector serverSelector = Selector.open();
            serverSocketChannel.register(serverSelector, SelectionKey.OP_ACCEPT);

            int position = 0;
            while (true) {
                serverSelector.select();

                Iterator<SelectionKey> iterator = serverSelector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    iterator.remove();
                    // 处理连接建立事件
                    if (selectionKey.isAcceptable()) {
                        SocketChannel socketChannel = ((ServerSocketChannel) selectionKey.channel()).accept();
                        socketChannel.configureBlocking(false);
                        workers.get(position % workers.size()).registry(socketChannel);
                        position ++;
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public Thread getBossThread() {
        return bossThread;
    }
}
